
/**
 * @file	handler.c
 * @brief
 * @author
 * @date
 * @note
 * @see
 * @version $Id$
**/

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "public.h"
#include "protocol.h"
#include "handle.h"

#define DEF_MSGMAX  128

struct msg_handle_t
{
	int num;
	msg_handler_t handler;
};

static int msg_cnt;
struct msg_handle_t msg_set[DEF_MSGMAX];

static int msg_ishave(struct u_session_t *session);

// 消息初始化.
int msg_init()
{
	int i;

	msg_cnt = 0;

	for(i=0; i<DEF_MSGMAX; i++) {
		msg_set[i].num = -1;
		msg_set[i].handler = NULL;
	}

	return 0;
}

// 添加一条消息.
int msg_add(int msgnum, msg_handler_t handler)
{
	if(msg_cnt > DEF_MSGMAX) {
		return -1;
	}

	msg_set[msg_cnt].num = msgnum;
	msg_set[msg_cnt].handler = handler;

	msg_cnt++;

	return 0;
}

// 删除一条消息.
int msg_del(int msgnum)
{
	int i=0;

	for(i=0;i<msg_cnt;i++)
	{
		if(msg_set[i].num == msgnum) {
			msg_set[i].num = msg_set[msg_cnt-1].num;
			msg_set[i].handler = msg_set[msg_cnt-1].handler;
			msg_set[msg_cnt-1].num = -1;
			msg_set[msg_cnt-1].handler = NULL;
			msg_cnt--;
			break;
		}
	}

	return 0;
}

// 是否有完整消息.
static int msg_ishave(struct u_session_t *session)
{
	struct proto_head_t *protohead;

	// 长度不够.
	if(session->recvlen < sizeof(struct proto_head_t)) {
		return -1;
	}

	protohead = (struct proto_head_t *)session->recvbuf;

	// 消息不完整.
	if(session->recvlen < protohead->len+sizeof(struct proto_head_t)) {
		return -1;
	}

	// 版本号不对.
	if(protohead->magic != MAGICNUM) {
		return -2;
	}

	return 0;
}

// 处理消息.
int msg_exec(struct u_session_t *session)
{
	struct proto_head_t *protohead;
	int i=0;
	int msg_len = 0;
	char *data;

	// 有完整消息.
	while(msg_ishave(session) == 0) {
		protohead = (struct proto_head_t *)session->recvbuf;

		data = session->recvbuf+sizeof(struct proto_head_t);
		msg_len = sizeof(struct proto_head_t) + protohead->len;

		// 查找消息处理函数.
		for(i=0;i<msg_cnt;i++)
		{
			if(msg_set[i].num == protohead->num) {
				// 处理消息.
				msg_set[i].handler(session, data, protohead->len);
				break;
			}
		}
		memmove(session->recvbuf, session->recvbuf+msg_len,
			session->recvlen-msg_len);
		session->recvlen -= msg_len;
	}

	// 消息错误.
	if(msg_ishave(session) == -2) {
		session->recvlen=0;
	}

	return 0;
}

